/**
 * 泛型在函数中的使用
 */
const getArray = <T>(value: T, times: number = 5): T[] => {
    return new Array(times).fill(value)
}
console.log(getArray("2"));

const getArray2 = <T, U>(value: T, value2: U): [T, U] => {
    return [value, value2]
}
console.log(getArray2("2", 2));

const getArray3 = <T, U>(value: T, value2: U): [T, U][] => {
    return [[value, value2], [value, value2]]
}
console.log(getArray3("2", 2));
console.log(getArray3<string, number>("2", 2));

/**
 * 使用泛型定义函数类型
 */
let getArr: <T>(arg: T, times: number) => T[]
getArr = (arg: any, times: number) => {
    return new Array(times).fill(arg)
}
console.log(getArr("12345", 3).map(item => item.length));

/**
 * 类型别名定义函数类型
 */
type GetArray = <T>(arg: T, times: number) => T[]

/**
 * 使用接口定义函数类型
 */
interface IGetArray {
    // tslint:disable-next-line: callable-types
    <T>(arg: T, times: number): T[] // 根据参数的类型自动获取类型
}
let fn: IGetArray
fn = (arg, times) => { return new Array(times).fill(arg) }
console.log(fn(3, 4));


interface IGetArray2<T> {
    // tslint:disable-next-line: callable-types
    (arg: T, times: number): T[]
}
let fn2: IGetArray2<string> // 定义时指定的类型
fn2 = (arg, times) => { return new Array(times).fill(arg) }
console.log(fn2("3", 4));

/**
 * 泛型约束
 */
// 泛型必须要有lenght属性
interface ValueWithLength {
    length: number
}
let fn3 = <T extends ValueWithLength>(arg: T) => { return new Array(arg.length).fill(arg) }
console.log(fn3("123"));

/**
 * keyof 索引约束，K是T中的一个索引
 */
const getProps = <T, K extends keyof T>(object: T, propName: K) => {
    return object[propName]
}
const objs = {
    a: "aa",
    b: "bb"
}

console.log(getProps(objs, "a"));
